package ru.ifmo.votinov;

import universum.bi.Location;
import universum.bi.BeingInterface;
import universum.bi.Constants;

import java.util.List;
import java.util.ArrayList;

class SearchUtil {
    static float moveCost(ConquerorBeing being) {
        return Constants.K_movecost * being.getParams().S + Constants.K_masscost * being.getMass();
    }

    static int movesCount(Location from, Location to, ConquerorBeing being) {
        int speed = (int)being.getSpeed();
        int dx = Math.abs(from.getX() - to.getX());
        int dy = Math.abs(from.getY() - to.getY());
        dx = Math.min(dx, Constants.getWidth() - dx);
        dy = Math.min(dy, Constants.getHeight() - dy);

        return (int)Math.ceil(((float)Math.max(dx, dy)) / speed);
    }

    static float moveCost(Location from, Location to, ConquerorBeing being) {
        return moveCost(being) * movesCount(from, to, being);
    }

    static Location stepToward(BeingInterface bi, ConquerorBeing being, Location to) {
        Location from = bi.getPointInfo(being).getLocation();
        float speed = being.getParams().S;

        float d = bi.distance(from, to);

        if (d <= speed) {
            return to;
        }

        int x1 = from.getX(), y1 = from.getY();
        int x2 = to.getX(),   y2 = to.getY();

        // X distance
        int dx1 = Math.abs(x2 - x1);
        int dx = Math.min(dx1, Constants.getWidth() - dx1);
        // Y distance
        int dy1 = Math.abs(y2 - y1);
        int dy = Math.min(dy1, Constants.getHeight() - dy1);

        int signx = (x1 == x2) ? 0 : (dx1 == x2 - x1) ? 1 : -1;
        int signy = (y1 == y2) ? 0 : (dy1 == y2 - y1) ? 1 : -1;

        if (Constants.getWidth() - dx1 < dx1) {
            signx = -signx;
        }
        if (Constants.getHeight() - dy1 < dy1) {
            signy = -signy;
        }
        int s = (int)speed;

        int xd = Math.min(dx, s) * signx;
        int yd = Math.min(dy, s) * signy;
        // [BEGIN] modified by cpp
        //return new Location(normal(x1+xd,Constants.getWidth()), normal(y1+yd, Constants.getHeight()));
        return bi.createLocation(normal(x1+xd,Constants.getWidth()),normal(y1+yd, Constants.getHeight()) );
        // [END] modified by cpp
    }

    private static int normal(int x, int max) {
        return (x + max) % max;
    }

    static int stepsCanMake(ConquerorBeing being) {
        return (int)Math.floor((being.getEnergy() - Constants.K_emin * being.getMass()) / moveCost(being));
    }

    static Location getClosestLocation(BeingInterface bi, Location location, List<Location> variants) {
        float minDistance = Float.MAX_VALUE;
        Location closestLocation = null;
        for (Location variant : variants) {
            float distance = bi.distance(location, variant);
            if (distance < minDistance) {
                minDistance = distance;
                closestLocation = variant;
            }
        }
        return closestLocation;
    }

    static List<Location> getClosestSeekLocations(BeingInterface bi, Location curLocation, List<Location> locations) {
        List<Location> closestLocations = new ArrayList<Location>();
        float minDistance = Float.MAX_VALUE;
        for (Location seekLocation : locations) {
            if (seekLocation == curLocation) {
                continue;
            }
            float distance = bi.distance(curLocation, seekLocation);
            if (distance < minDistance) {
                minDistance = distance;
                closestLocations.clear();
                closestLocations.add(seekLocation);
            } else if (distance == minDistance) {
                closestLocations.add(seekLocation);
            }
        }
        return closestLocations;
    }
}
